/*
#include <io_extend.h>
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-09-28     SenyPC       the first version
 */
#include "device_data.h"
#include "device_io.h"
#include "io_extend.h"

#include <stdlib.h>

#define DBG_TAG "device_io"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>


static int io_ext_config_set(uint16_t type,int di_nums, int do_nums) {
    device_extend_config_t config = _ext_config;
    if(NULL == config) {
        config = dev_extend_malloc(sizeof(struct device_extend_config));
        if(NULL != config) {
            config->type = type;
            config->di_nums = di_nums;
            config->do_nums = do_nums;
            config->pre = NULL;
            config->next = NULL;

            _ext_config = config;
            _ext_config_nums++;
        }
    } else {
        if(type == config->type){
            config->di_nums = di_nums;
            config->do_nums = do_nums;
            return 0;
        }
        while(NULL != config->next) {
            config = config->next;
            if(type == config->type){
                config->di_nums = di_nums;
                config->do_nums = do_nums;
                return 0;
            }
        }
        device_extend_config_t config_temp = dev_extend_malloc(sizeof(struct device_extend_config));
        if(NULL != config_temp) {
            config_temp->type = type;
            config_temp->di_nums = di_nums;
            config_temp->do_nums = do_nums;
            config_temp->pre = config;
            config_temp->next = NULL;

            config->next = config_temp;
            _ext_config_nums++;
        }
    }
    return 0;
}

static int io_ext_config_init( void ) {
    io_ext_config_set(0x11, 8, 8);
    return 0;
}
INIT_DEVICE_EXPORT(io_ext_config_init);

int io_ext_data_init(device_extend_data_t data, int di_nums, int do_nums) {
    data->di_nums = di_nums;
    data->do_nums = do_nums;
    return 0;
}

uint8_t io_get_ext_di(int pin) {
    int ret = MODBUS_RT_EOK;
    uint8_t val = 0;
    device_extend_dev_t data_dev = &_ext_data;
    if(pin < (_io_di_setting_nums + data_dev->di_nums)) {
        //控制外部
        int pin_addr = _io_di_setting_nums;
        device_extend_data_t data_list = data_dev->data_list;
        for(int i = 0; i < data_dev->dev_nums; i++) {
            if(pin < (pin_addr + data_list->di_nums)) {
                //执行代码
                int addr_temp = pin - pin_addr;
                if(MODBUS_RT_EOK != (ret = modbus_rtu_excuse(data_dev->com_dev, data_list->addr, AGILE_MODBUS_FC_READ_DISCRETE_INPUTS,
                        DEV_X_BIT_ADDR + addr_temp, 1, &val))) {
                    return -ret;
                }
                return val;
            }
            pin_addr += data_list->di_nums;
            data_list = data_list->next;
        }
        return -MODBUS_RT_ERROR;

    } else if(pin < DEV_X_BIT_NUMS) {
        return dev_di_data[pin];
    }
    return 0;
}


uint8_t io_get_ext_do(int pin) {
    int ret = MODBUS_RT_EOK;
    uint8_t val = 0;
    device_extend_dev_t data_dev = &_ext_data;
    if(pin < (_io_do_setting_nums + data_dev->do_nums)) {
        //控制外部
        int pin_addr = _io_do_setting_nums;
        device_extend_data_t data_list = data_dev->data_list;
        for(int i = 0; i < data_dev->dev_nums; i++) {
            if(pin < (pin_addr + data_list->do_nums)) {
                //执行代码
                int addr_temp = pin - pin_addr;
                if(MODBUS_RT_EOK != (ret = modbus_rtu_excuse(data_dev->com_dev, data_list->addr, AGILE_MODBUS_FC_READ_COILS,
                        DEV_Y_BIT_ADDR + addr_temp, 1, &val))) {
                    return -ret;
                }
                return val;
            }
            pin_addr += data_list->do_nums;
            data_list = data_list->next;
        }
        return -MODBUS_RT_ERROR;

    } else if(pin < DEV_Y_BIT_NUMS) {
        return dev_do_data[pin];
    }
    return 0;

}

int io_set_ext_do(int pin, rt_base_t value) {
    int ret = MODBUS_RT_EOK;
    uint8_t val = value;
    device_extend_dev_t data_dev = &_ext_data;
    if(pin < (_io_do_setting_nums + data_dev->do_nums)) {
        //控制外部
        int pin_addr = _io_do_setting_nums;
        device_extend_data_t data_list = data_dev->data_list;
        for(int i = 0; i < data_dev->dev_nums; i++) {
            if(pin < (pin_addr + data_list->do_nums)) {
                //执行代码
                int addr_temp = pin - pin_addr;
                if(MODBUS_RT_EOK != (ret = modbus_rtu_excuse(data_dev->com_dev, data_list->addr, AGILE_MODBUS_FC_WRITE_SINGLE_COIL,
                        DEV_Y_BIT_ADDR + addr_temp, 1, &val))) {
                    return -ret;
                }
                return val;
            }
            pin_addr += data_list->do_nums;
            data_list = data_list->next;
        }
        return -MODBUS_RT_ERROR;

    } else if(pin < DEV_Y_BIT_NUMS) {
        dev_do_data[pin] = value;
    }
    return 0;
}


int io_read_ext_di(int start_addr, int nums, uint8_t *val) {
    int ret = MODBUS_RT_EOK;
    device_extend_dev_t data_dev = &_ext_data;
    int pin_start = start_addr;
    int pin_nums = nums;
    uint8_t *pin_val= val;
    if(pin_start < (_io_di_setting_nums + data_dev->di_nums)) {
        //控制外部
        int pin_addr = _io_di_setting_nums;
        device_extend_data_t data_list = data_dev->data_list;
        for(int i = 0; i < data_dev->dev_nums; i++) {
            if(pin_start < (pin_addr + data_list->di_nums)) {
                int quantity = 0;
                if((pin_start + pin_nums) < (pin_addr + data_list->di_nums)) {
                    quantity = pin_nums;
                } else {
                    quantity = (pin_addr + data_list->di_nums) - pin_start;
                }
                //执行代码
                int addr_temp = pin_start - pin_addr;
                if(MODBUS_RT_EOK != (ret = modbus_rtu_excuse(data_dev->com_dev, data_list->addr, AGILE_MODBUS_FC_READ_DISCRETE_INPUTS,
                        DEV_X_BIT_ADDR + addr_temp, quantity, pin_val))) {
                    return -ret;
                }
                pin_nums -= quantity;
                if(0 >= pin_nums) {
                    return MODBUS_RT_EOK;
                } else {
                    pin_start += quantity;
                    pin_val += quantity;
                }
            }
            pin_addr += data_list->di_nums;
            data_list = data_list->next;
        }
        if(0 < pin_nums) {
            memcpy(pin_val, &dev_di_data[pin_start], pin_nums);
        }
    } else if(pin_start < DEV_X_BIT_NUMS) {
        memcpy(pin_val, &dev_di_data[pin_start], pin_nums);
    }
    return 0;
}


int io_read_ext_do(int start_addr, int nums, uint8_t *val) {
    int ret = MODBUS_RT_EOK;
    device_extend_dev_t data_dev = &_ext_data;
    int pin_start = start_addr;
    int pin_nums = nums;
    uint8_t *pin_val= val;
    if(pin_start < (_io_do_setting_nums + data_dev->do_nums)) {
        //控制外部
        int pin_addr = _io_do_setting_nums;
        device_extend_data_t data_list = data_dev->data_list;
        for(int i = 0; i < data_dev->dev_nums; i++) {
            if(pin_start < (pin_addr + data_list->do_nums)) {
                int quantity = 0;
                if((pin_start + pin_nums) < (pin_addr + data_list->do_nums)) {
                    quantity = pin_nums;
                } else {
                    quantity = (pin_addr + data_list->do_nums) - pin_start;
                }
                //执行代码
                int addr_temp = pin_start - pin_addr;
                if(MODBUS_RT_EOK != (ret = modbus_rtu_excuse(data_dev->com_dev, data_list->addr, AGILE_MODBUS_FC_READ_COILS,
                        DEV_Y_BIT_ADDR + addr_temp, quantity, pin_val))) {
                    return -ret;
                }
                pin_nums -= quantity;
                if(0 >= pin_nums) {
                    return MODBUS_RT_EOK;
                } else {
                    pin_start += quantity;
                    pin_val += quantity;
                }
            }
            pin_addr += data_list->do_nums;
            data_list = data_list->next;
        }
        if(0 < pin_nums) {
            memcpy(pin_val, &dev_do_data[pin_start], pin_nums);
        }
    } else if(pin_start < DEV_Y_BIT_NUMS) {
        memcpy(pin_val, &dev_do_data[pin_start], pin_nums);
    }
    return 0;
}

int io_write_ext_do(int start_addr, int nums, uint8_t *val) {
    int ret = MODBUS_RT_EOK;
    device_extend_dev_t data_dev = &_ext_data;
    int pin_start = start_addr;
    int pin_nums = nums;
    uint8_t *pin_val= val;
    if(pin_start < (_io_do_setting_nums + data_dev->do_nums)) {
        //控制外部
        int pin_addr = _io_do_setting_nums;
        device_extend_data_t data_list = data_dev->data_list;
        for(int i = 0; i < data_dev->dev_nums; i++) {
            if(pin_start < (pin_addr + data_list->do_nums)) {
                int quantity = 0;
                if((pin_start + pin_nums) < (pin_addr + data_list->do_nums)) {
                    quantity = pin_nums;
                } else {
                    quantity = (pin_addr + data_list->do_nums) - pin_start;
                }
                //执行代码
                int addr_temp = pin_start - pin_addr;
                if(MODBUS_RT_EOK != (ret = modbus_rtu_excuse(data_dev->com_dev, data_list->addr, AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS,
                        DEV_Y_BIT_ADDR + addr_temp, quantity, pin_val))) {
                    return -ret;
                }
                pin_nums -= quantity;
                if(0 >= pin_nums) {
                    return MODBUS_RT_EOK;
                } else {
                    pin_start += quantity;
                    pin_val += quantity;
                }
            }
            pin_addr += data_list->do_nums;
            data_list = data_list->next;
        }
        if(0 < pin_nums) {
            memcpy(&dev_do_data[pin_start], pin_val, pin_nums);
        }
    } else if(pin_start < DEV_Y_BIT_NUMS) {
        memcpy(&dev_do_data[pin_start], pin_val, pin_nums);
    }
    return 0;
}

